package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.common.cache.GmallCache;
import com.atguigu.gmall.common.constans.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.model.product.*;
import com.atguigu.gmall.product.mapper.*;
import com.atguigu.gmall.product.service.levelService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class levelServiceImpl implements levelService {

    @Autowired
    private BaseCategory1Mapper baseCategory1Mapper;

    @Autowired
    private BaseCategory2Mapper baseCategory2Mapper;

    @Autowired
    private BaseCategory3Mapper baseCategory3Mapper;

    @Autowired
    private BaseAttrInfoMapper baseAttrInfoMapper;

    @Autowired
    private BaseAttrValueMapper baseAttrValueMapper;

    @Autowired
    private BaseTrademarkMapper baseTrademarkMapper;

    @Autowired
    private SpuInfoMapper spuInfoMapper;

    @Autowired
    private SpuSaleAttrMapper spuSaleAttrMapper;

    @Autowired
    private BaseSaleAttrMapper baseSaleAttrMapper;

    @Autowired
    private SpuImageMapper spuImageMapper;

    @Autowired
    private SkuImageMapper skuImageMapper;

    @Autowired
    private SpuSaleAttrValueMapper spuSaleAttrValueMapper;

    @Autowired
    private  SkuInfoMapper skuInfoMapper;

    @Autowired
    private SkuAttrValueMapper skuAttrValueMapper;

    @Autowired
    private SkuSaleAttrValueMapper skuSaleAttrValueMapper;

    @Autowired
    private BaseCategoryViewMapper baseCategoryViewMapper;


    //一级查询
    @Override
    public List<BaseCategory1> getCategory1() {
        return baseCategory1Mapper.selectList(null);
    }

    //二级查询
    @Override
    public List<BaseCategory2> getCategory2(Long category1id) {
        return baseCategory2Mapper.selectList(new QueryWrapper<BaseCategory2>()
                .eq("category1_id",category1id));
    }

    //三级查询
    @Override
    public List<BaseCategory3> getCategory3(Long category2Id) {
        return baseCategory3Mapper.selectList(new QueryWrapper<BaseCategory3>()
        .eq("category2_id",category2Id));
    }

    //根据分类id获取平台属性
    @Override
    public List<BaseAttrInfo> attrInfoList(Long category1Id, Long category2Id, Long category3Id) {
        //二表联查
        return baseAttrInfoMapper.attrInfoList(category1Id,category2Id,category3Id);

    }

    //添加平台属性
    @Override
    @Transactional
    public void saveAttrInfo(BaseAttrInfo baseAttrInfo) {
        //添加属性
        baseAttrInfoMapper.insert(baseAttrInfo);
        //添加属性值
            //①获取属性值
        List<BaseAttrValue> attrValueList = baseAttrInfo.getAttrValueList();
            //②遍历
    if (!CollectionUtils.isEmpty(attrValueList)){
        attrValueList.forEach(attrValue ->{
            //设置外键
            attrValue.setAttrId(baseAttrInfo.getId());
            baseAttrValueMapper.insert(attrValue);
        });
    }
    }

    //根据平台属性ID获取平台属性
    @Override
    public BaseAttrInfo getAttrInfo(Long attrId) {
        BaseAttrInfo baseAttrInfo = baseAttrInfoMapper.selectById(attrId);
        //查询到最新的平台属性值集合数据放入平台属性中
        baseAttrInfo.setAttrValueList(getAttrValueList(attrId));
        return baseAttrInfo;
    }

    //获取品牌分页列表
    @Override
    public IPage baseTrademark(Integer page, Integer limit) {
        return baseTrademarkMapper.selectPage(new Page<BaseTrademark>(page,limit),null);
    }

    //品牌添加
    @Override
    public void baseTrademarksave(BaseTrademark baseTrademark) {
        baseTrademarkMapper.insert(baseTrademark);
    }

    //查询SPU的分页结果集
    @Override
    public IPage spuPage(Integer page, Integer limit, Long category3Id) {
        return spuInfoMapper.selectPage(new Page<SpuInfo>(page,limit),
                new QueryWrapper<SpuInfo>().eq("category3_Id",category3Id));

    }

    //添加spu 品牌下拉框
    @Override
    public List<BaseTrademark> getTrademarkList() {
        return baseTrademarkMapper.selectList(null);
    }

    //添加SPU 之 销售属性下拉框
    @Override
    public List<BaseSaleAttr> baseSaleAttrList() {
        return baseSaleAttrMapper.selectList(null);
    }

    //SPU添加
    @Override
    public void saveSpuInfo(SpuInfo spuInfo) {
        //添加属性
        spuInfoMapper.insert(spuInfo);
        //添加 spu_image
        List<SpuImage> spuImageList = spuInfo.getSpuImageList();
        spuImageList.forEach(spuImage->{
            spuImage.setSpuId(spuInfo.getId());
            spuImageMapper.insert(spuImage);
        });
        //添加 spu_sale_attr
        List<SpuSaleAttr> spuSaleAttrList = spuInfo.getSpuSaleAttrList();
        spuSaleAttrList.forEach(spuSaleAttr->{
            spuSaleAttr.setSpuId(spuInfo.getId());
            spuSaleAttrMapper.insert(spuSaleAttr);
            //添加 spu_sale_attr_Value
            List<SpuSaleAttrValue> spuSaleAttrValueList = spuSaleAttr.getSpuSaleAttrValueList();
            spuSaleAttrValueList.forEach(spuSaleAttrValue->{
                spuSaleAttrValue.setSpuId(spuInfo.getId());
                spuSaleAttrValue.setSaleAttrName(spuSaleAttr.getSaleAttrName());
                spuSaleAttrValueMapper.insert(spuSaleAttrValue);
            });
        });
    }

    //根据SpuID查询所有此商品的图片  bigint
    @Override
    public List<SpuImage> spuImageList(Long spuId) {
        return spuImageMapper.selectList(new QueryWrapper<SpuImage>()
                .eq("spu_id",spuId));
    }

    //根据spuId获取销售属性
    @Override
    public List<SpuSaleAttr> spuSaleAttrList(Long spuId) {
        return spuSaleAttrMapper.spuSaleAttrList(spuId);

    }

    //保存SKU
    @Override
    public void saveSkuInfo(SkuInfo skuInfo) {
        //1:sku_info
        skuInfoMapper.insert(skuInfo);
        //2:sku_image
        List<SkuImage> skuImageList = skuInfo.getSkuImageList();
        skuImageList.forEach(skuImage -> {
            skuImage.setSkuId(skuInfo.getId());
            skuImageMapper.insert(skuImage);
        });

        //3:sku_SaleAttrValue
        skuInfo.getSkuSaleAttrValueList().forEach(skuSaleAttrValue -> {
            skuSaleAttrValue.setSkuId(skuInfo.getId());
            skuSaleAttrValue.setSpuId(skuInfo.getSpuId());
            skuSaleAttrValueMapper.insert(skuSaleAttrValue);
        });
        //4:sku_Attr_Value
        skuInfo.getSkuAttrValueList().forEach(skuAttrValue -> {
            skuAttrValue.setSkuId(skuInfo.getId());
            skuAttrValueMapper.insert(skuAttrValue);
        });
    }

    //获取sku分页列表
    @Override
    public IPage skuPage(Integer page, Integer limit) {
        return skuInfoMapper.selectPage(new Page<SkuInfo>(page,limit),null );
    }

    @Autowired
    private RabbitService rabbitService;
    //上架
    @Override
    public void onSale(Long skuId) {
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setIsSale(SkuInfo.ISSALE);
        skuInfo.setId(skuId);
        //更新操作
        skuInfoMapper.updateById(skuInfo);
        //要发消息  给ES索引库 进行添加索引
        rabbitService.sendMessage(
                MqConst.EXCHANGE_DIRECT_GOODS,
                MqConst.ROUTING_GOODS_UPPER,
                 skuId);
    }

    //下架
    @Override
    public void cancelSale(Long skuId) {
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setIsSale(SkuInfo.NOSALE);//上架
        skuInfo.setId(skuId);
        //更新操作
        skuInfoMapper.updateById(skuInfo);
        //要发消息 删除ES中的索引
        rabbitService.sendMessage(
                MqConst.EXCHANGE_DIRECT_GOODS,
                MqConst.ROUTING_GOODS_LOWER,
                skuId);
    }


    //根据skuId查询sku_info  根据skuId查询sku_image
    @Override
    public SkuInfo getSkuInfo(Long skuId) {
        String cacheKey = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKUKEY_SUFFIX;
        //分布式锁的Key
        String cacheKeyLock = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKULOCK_SUFFIX;

        //1:先查询缓存  SkuInfo
        SkuInfo skuInfo = (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
        if(null == skuInfo) {

            //分布式锁 ：  解决：缓存的击穿问题
            String uuid = UUID.randomUUID().toString();
            Boolean isLock = redisTemplate.opsForValue().
                    setIfAbsent(cacheKeyLock, uuid, 2, TimeUnit.SECONDS);
            if(isLock){
                //获取到了锁
                try {
                    //1.2:没有  查询DB 放到缓存中
                    skuInfo = skuInfoMapper.selectById(skuId);
                    //1.3:判断从DB中查询是否有数据
                    if (null != skuInfo) {
                        //1.3.1 : 有
                        //根据skuId查询sku_image
                        List<SkuImage> skuImageList = skuImageMapper.
                                selectList(new QueryWrapper<SkuImage>().eq("sku_id", skuId));
                        skuInfo.setSkuImageList(skuImageList);
                        //放到缓存中  过期时间
                        redisTemplate.opsForValue().set(cacheKey, skuInfo, //解决缓存雪崩
                                RedisConst.SKUKEY_TIMEOUT + new Random().nextInt(300)
                                , TimeUnit.SECONDS);
                    } else {
                        //1.3.2: 没有  空结果  解决缓存的穿透问题
                        skuInfo = new SkuInfo();//对象中没有任何数据叫空结果
                        redisTemplate.opsForValue().set(cacheKey, skuInfo, 5, TimeUnit.MINUTES);
                    }
                } finally {
                    //解锁
                    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return tostring(redis.call('del',KEYS[1])) else return 0 end";
                    //执行上面的LUA脚本
                    this.redisTemplate.execute(new DefaultRedisScript<>(script),
                            Collections.singletonList(cacheKeyLock), uuid);
                }
            }else{
                //直接查询缓存
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                    return (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return skuInfo;
    }

    //2:查询实时价格   优化的时候 不要放进缓存中
    @Override
    public BigDecimal getPrice(Long skuId) {
        QueryWrapper<SkuInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("price").eq("id",skuId);
        SkuInfo skuInfo = skuInfoMapper.selectOne(queryWrapper);
        if (skuInfo !=null){
            return skuInfo.getPrice();
        }
        return null;
    }

//    //3、根据category3Id查询一二三级分类
//    //代码优化
      //这段代码有问题
//    @Override
//    public BaseCategoryView getCategoryView(Long category3Id) {
//        //设数据的key值
//        String cacheKey = RedisConst.GETCATEGORYVIEW +category3Id;
//        //设置锁Key值
//        String cacheKeyLock = RedisConst.GETCATEGORYVIEW +category3Id;
//        //先查缓存
//        BaseCategoryView baseCategoryView = (BaseCategoryView) redisTemplate.opsForValue().get(cacheKey);
//        //判断缓存中是否有数据
//        if (baseCategoryView ==null){
//            //分布式锁 ：解决缓存击穿问题
//            String uuid = UUID.randomUUID().toString();
//            Boolean isLock = redisTemplate.opsForValue().setIfAbsent(cacheKeyLock, uuid, 2, TimeUnit.SECONDS);
//            if (isLock){
//                //拿到了锁
//                try {
//                    //缓存中没有数据 查询DB
//                    baseCategoryView =baseCategoryViewMapper.selectById(category3Id);
//                    //判断是否从DB中获取到数据
//                    if (baseCategoryView != null){
//                        //获取到了数据  放到缓存中 设置过期时间
//                        redisTemplate.opsForValue().set(cacheKey,baseCategoryView,RedisConst.SKUKEY_TIMEOUT +new Random().nextInt(300));
//
//                    }else {
//                       //没有获取到数据 就是 缓存中和数据库中都没有数据  空结果
//                        //解决：缓存穿透问题
//                        baseCategoryView = new BaseCategoryView(); //对象中没有任何数据叫空结果
//                        redisTemplate.opsForValue().set(cacheKey,baseCategoryView,5,TimeUnit.MINUTES);
//                    }
//                } finally {
//                    //解锁
//                    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return tostring(redis.call('del',KEYS[1])) else return 0 end";
//                    //执行上面的LUA脚本
//                    this.redisTemplate.execute(new DefaultRedisScript<>(script),
//                            Collections.singletonList(cacheKeyLock), uuid);
//                }
//            }else {
//                //没有获取到锁的查缓存
//                try {
//                    TimeUnit.MILLISECONDS.sleep(500);
//                    return (BaseCategoryView) redisTemplate.opsForValue().get(cacheKey);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
//        return baseCategoryView;
//    }

    //根据category3Id查询一二三级分类
    @Override
    @GmallCache(prefix = "getCategoryView:")
    public BaseCategoryView getCategoryView(Long category3Id) {
        return baseCategoryViewMapper.selectById(category3Id);
    }

    //4、根据spuId查询spu_sale_attr_value(被选中项）  商品ID spu  库存ID
    @Override
    @GmallCache(prefix = "getSpuSaleAttrValue:")
    public List<SpuSaleAttr> getSpuSaleAttrValue(Long skuId, Long spuId) {
        List<SpuSaleAttr> spuSaleAttrListCheckBySku = spuSaleAttrMapper.getSpuSaleAttrListCheckBySku(skuId, spuId);
        if(org.springframework.util.CollectionUtils.isEmpty(spuSaleAttrListCheckBySku)){
            return null;
        }else{
            return spuSaleAttrListCheckBySku;
        }
    }

    //5、skuId与销售属性组合
    @Override
    @GmallCache(prefix = "spuValueIdsMap:")
    public Map spuValueIdsMap(Long spuId) {
        Map result = new HashMap();
        List<Map> skuValueIdsMap = skuSaleAttrValueMapper.getSkuValueIdsMap(spuId);
        skuValueIdsMap.forEach(map->{
            result.put(map.get("value_ids"),map.get("sku_id"));
        });
        return result;
    }

    //首页商品分类实现
    @Override
    public List<BaseCategoryView> getBaseCategoryList() {
        List<BaseCategoryView> baseCategoryViewList = baseCategoryViewMapper.selectList(null);
        return baseCategoryViewList;
    }

    //查询品牌
    @Override
    public BaseTrademark getBaseTrademarkById(Long tmId) {
        return baseTrademarkMapper.selectById(tmId);
    }

    //根据skuId 查询平台属性及属性值
    @Override
    public List<SkuAttrValue> getSkuAttrValueList(Long skuId) {
        return skuAttrValueMapper.getSkuAttrValueList(skuId);
    }


    private List<BaseAttrValue> getAttrValueList(Long attrId) {
        QueryWrapper<BaseAttrValue> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("attr_id",attrId);
        List<BaseAttrValue> baseAttrValueList = baseAttrValueMapper.selectList(queryWrapper);
        return baseAttrValueList;
    }

    @Autowired
    private RedisTemplate redisTemplate;
}
